#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Connection.hpp"
#include "Protocol.hpp"
#include "Calculate.hpp"

class HandlerConnection
{
    const static int buffer_size = 1024;

public:
    static void HandlerRequest(Connection *conn)
    {
        std::string &inbuffer = conn->InBuffer();
        std::string message; // 完成报文

        CalCulate_Ns::Calculate calculate;
        Protocol::Factory facory;

        auto request = facory.BuildRequest();

        // 1. 明确报文边界  解决粘包问题
        while (Protocol::Decode(inbuffer, &message))
        {
            // message 一定是一个完整的报文,符合协议的

            // 2. 反序列化
            if (!request->DeSerialize(message))
            {
                // 不能处理一个完整的报文,那么就返回继续
                continue;
            }

            //  3. 业务处理
            auto response = calculate.Cal(request);

            // 4. 对响应进行反序列化
            std::string response_str;
            response->Serialize(&response_str);

            // 5. 封装完整报文
            response_str = Protocol::Encode(response_str);

            // 6. 将发送的内容放到发送缓冲区
            conn->AddOutBuffer(response_str);
        }

        if (conn->OutBufferEmpty())
        {
            // 发送缓冲区,如果不是空,那么就开始发数据
            conn->_sender(conn);
        }
    }

    // 这里只关心将数据进行读取
    static void recver(Connection *conn)
    {
        errno = 0;
        // 读取
        char buffer[buffer_size];
        while (true)
        {

            ssize_t n = recv(conn->Sockfd(), buffer, buffer_size - 1, 0); // 非阻塞读取
            if (n > 0)
            {
                buffer[n] = 0;
                conn->AddInbuffer(buffer);
            }
            else
            {
                if (errno == EAGAIN) // 本轮已经读取完毕了,下次再来吧
                {
                    break;
                }

                if (errno == EINTR) // 被信号中断
                {
                    continue;
                }
                else
                {
                    // 出错
                    conn->_excepter(conn);
                    return;
                }
            }
        }

        // 分析处理报文
        // 需要协议 判断报文是否完整
        HandlerRequest(conn);
        std::cout << conn->InBuffer() << std::endl;
    }

    static void sender(Connection *conn)
    {
        std::string &outbuffer = conn->OutBuffer();
        while (true)
        {
            ssize_t n = send(conn->Sockfd(), outbuffer.c_str(), outbuffer.size(), 0);
            if (n >= 0)
            {
                // * 如果返回值为0,那么说明 send 函数发送了一个空串
                outbuffer.erase(0, n); // 将已经发送的内容移除
                if (outbuffer.empty())
                {
                    // 如果已经发送完毕,那么就返回
                    break;
                }
            }
            else
            {
                if (errno == EAGAIN) // 本轮已经读取完毕了,下次再来吧
                {
                    break;
                }

                if (errno == EINTR) // 被信号中断
                {
                    continue;
                }
                else
                {
                    // 出错
                    conn->_excepter(conn);
                    return;
                }
            }
        }

        // 走到这里,说明是从 break 处退出的,本次缓冲区已经被 //* 发满了 或者 全部发送完毕,结束了
        // 但是当前进入这个函数只有一次机会,//! 所以此时,需要 epoller 关心  !!!
        if (!conn->OutBufferEmpty())
        {
            // 如果这里还有数据没有发送完毕,就开启关系
            conn->R->EnableReadWrite(conn->Sockfd(), true, true);
        }
        else
        {
            // 全都发送完毕,可以关闭对写事件的关心
            conn->R->EnableReadWrite(conn->Sockfd(), true, false);
        }
    }

    static void excepter(Connection *conn)
    {
        lg.LogMessage(Info,"connection erase done, who: %d \n",conn->Sockfd());
        errno = 0;
        // 移除关心
        // delete coon
        // unordered_map 移除
        // 关闭 sockfd

        conn->R->RemoveConntion(conn->Sockfd());

        conn->Close();

        delete conn;
        
    }
};